package com.heu.blood.common.utils;



import java.util.Random;

public class GenerateNumberBySnowFlake {
   /**
    * 开始时间截 (2023-01-31)
    */

   private final long twepoch = 1675152067447L;

   /**
    * 机器id所占的位数
    */
   private final long workerIdBits = 10L;


   /**
    * 支持的最大机器id，结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
    */
   private final long maxWorkerId = -1L ^ (-1L << workerIdBits);


   /**
    * 序列在id中占的位数
    */
   private final long sequenceBits = 12L;

   /**
    * 机器ID向左移12位
    */
   private final long workerIdShift = sequenceBits;

   /**
    * 数据标识id向左移17位(12+5)
    */
   private final long datacenterIdShift = sequenceBits + workerIdBits;

   /**
    * 时间截向左移22位(5+5+12)
    */
   private final long timestampLeftShift = sequenceBits + workerIdBits ;

   /**
    * 生成序列的掩码，这里为4095 (0b111111111111=0xfff=4095)
    */
   private final long sequenceMask = -1L ^ (-1L << sequenceBits);

   /**
    * 工作机器ID(0~31)
    */
   private long workerId;

   /**
    * 数据中心ID(0~31)
    */
   private long datacenterId;

   /**
    * 毫秒内序列(0~4095)
    */
   private long sequence = 0L;

   /**
    * 上次生成ID的时间截
    */
   private long lastTimestamp = -1L;

   private String flag = "NN";


   public GenerateNumberBySnowFlake(String workerId, String flag) {

      if (workerId.equals("")) {
         throw new IllegalArgumentException("worker Id can't be null");
      }
      long tempid = 0l;
      Random random = new Random();
      for(int i = 0;i < workerId.length();i++){
         tempid += workerId.charAt(i) * random.nextInt(1000);
      }
      if(tempid > maxWorkerId){
         tempid = tempid-((tempid>>workerIdBits)<<workerIdBits);
      }
      this.workerId = tempid;
      this.flag = flag;
   }

   /**
    * 构造函数
    *
    * @param workerId     工作ID (0~2^10)
    */
   public GenerateNumberBySnowFlake(long workerId, String flag) {
      if (workerId < 0) {
         throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
      }
      if(workerId > maxWorkerId){
         workerId = workerId-((workerId>>workerIdBits)<<workerIdBits);
      }
      this.workerId = workerId;
      this.flag = flag;
   }


   // ==============================Methods==========================================

   /**
    * 获得下一个ID (该方法是线程安全的)
    *
    * @return SnowflakeId
    */
   public synchronized long nextId() {
      long timestamp = timeGen();

      //如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
      if (timestamp < lastTimestamp) {
         throw new RuntimeException(
                 String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
      }

      //如果是同一时间生成的，则进行毫秒内序列
      if (lastTimestamp == timestamp) {
         sequence = (sequence + 1) & sequenceMask;
         //毫秒内序列溢出
         if (sequence == 0) {
            //阻塞到下一个毫秒,获得新的时间戳
            timestamp = tilNextMillis(lastTimestamp);
         }
      }
      //时间戳改变，毫秒内序列重置
      else {
         sequence = 0L;
      }

      //上次生成ID的时间截
      lastTimestamp = timestamp;

      //移位并通过或运算拼到一起组成64位的ID

      return (((timestamp - twepoch) << timestampLeftShift)
              | (datacenterId << datacenterIdShift)
              | (workerId << workerIdShift)
              | sequence);
   }

   public synchronized String genNumberByflag(){

      long timestamp = timeGen();

      //如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
      if (timestamp < lastTimestamp) {
         throw new RuntimeException(
                 String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
      }

      //如果是同一时间生成的，则进行毫秒内序列
      if (lastTimestamp == timestamp) {
         sequence = (sequence + 1) & sequenceMask;
         //毫秒内序列溢出
         if (sequence == 0) {
            //阻塞到下一个毫秒,获得新的时间戳
            timestamp = tilNextMillis(lastTimestamp);
         }
      }
      //时间戳改变，毫秒内序列重置
      else {
         sequence = 0L;
      }

      //上次生成ID的时间截
      lastTimestamp = timestamp;

      //移位并通过或运算拼到一起组成64位的ID

//      Long l =  ;


      return flag + (((timestamp - twepoch) << timestampLeftShift)
              | (datacenterId << datacenterIdShift)
              | (workerId << workerIdShift)
              | sequence);
   }


   /**
    * 阻塞到下一个毫秒，直到获得新的时间戳
    *
    * @param lastTimestamp 上次生成ID的时间截
    * @return 当前时间戳
    */
   protected long tilNextMillis(long lastTimestamp) {
      long timestamp = timeGen();
      while (timestamp <= lastTimestamp) {
         timestamp = timeGen();
      }
      return timestamp;
   }

   /**
    * 返回以毫秒为单位的当前时间
    *
    * @return 当前时间(毫秒)
    */
   protected long timeGen() {
      return System.currentTimeMillis();
   }



}